package cn.ratel.route;

import cn.ratel.component.Handlers;
import cn.ratel.component.Routes;
import cn.ratel.exception.RatelException;
import com.google.common.base.Preconditions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.InvocationTargetException;

public class ActionHandler implements Handlers.Handler {
	private static Logger log = LoggerFactory.getLogger(ActionHandler.class);

	@Override
	public void handle(HandlerContext handlerContext) {
		String controllerName = handlerContext.getControllerName();
		Controller controller = Routes.me().getController(controllerName);
		if (controller == null) {
			throw new RatelException("can not find controller, uri=" + handlerContext.getUri(), RatelException.Cause._404);
		}

		Action action = controller.getAction(handlerContext.getActionName());
		if (action == null) {
			throw new RatelException("can not find action, uri=" + handlerContext.getUri(), RatelException.Cause._404);
		}

		Object target = controller.getControllerInstance();
		Object returnValue;
		try {
			returnValue = action.getMethod().invoke(target, action.getParams());
		} catch (IllegalAccessException | InvocationTargetException e) {
			throw new RuntimeException("invoke action error : " + e.getMessage(), e);
		}

		Preconditions.checkNotNull(returnValue, "return value of action can not be null");

		RenderProvider.Render render = RenderProvider.getRender(returnValue.getClass());
		Preconditions.checkNotNull(render, "can not find render for result type : " + action.getMethod().getReturnType());
		long start = System.currentTimeMillis();
		HttpServletRequest request = ContextHolder.getRequest().get();
		HttpServletResponse response = ContextHolder.getResponse().get();
		render.render(request, response, returnValue);
		long end = System.currentTimeMillis();
		log.debug("render view : {}ms", end - start);
	}


}
